/* i6d_ucase_sv.c

   A server that receives datagrams, converts their contents to uppercase, and
   then returns them to the senders.

   See also i6d_ucase_cl.c.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h> /*for bzero*/

#include "i6d_ucase.h"

static void errExit(char *msg) {
  perror(msg);
  exit(EXIT_FAILURE);
}

int main(int argc, char *argv[]) {
#ifdef IPV6
  struct sockaddr_in6 svaddr, claddr;
#else
  struct sockaddr_in svaddr, claddr;
#endif

  int sfd, j;
  ssize_t numBytes;
  socklen_t len;
  char buf[BUF_SIZE];
  char claddrStr[INET6_ADDRSTRLEN];

#ifdef IPV6
  /* Create a datagram socket bound to an address in the IPv6 domain */
  sfd = socket(AF_INET6, SOCK_DGRAM, 0);
  if (sfd == -1) errExit("socket");

  memset(&svaddr, 0, sizeof(struct sockaddr_in6));
  svaddr.sin6_family = AF_INET6;
  svaddr.sin6_addr = in6addr_any; /* Wildcard address */
  svaddr.sin6_port = htons(PORT_NUM);
#else
  sfd = socket(AF_INET, SOCK_DGRAM, 0);
  if (sfd == -1) errExit("socket");

  bzero(&svaddr, sizeof(svaddr));
  svaddr.sin_family = AF_INET;
  svaddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Wildcard address */
  svaddr.sin_port = htons(PORT_NUM);
#endif
  if (bind(sfd, (struct sockaddr *)&svaddr, sizeof(svaddr)) == -1) {
    errExit("bind");
  }

  /* Receive messages, convert to uppercase, and return to client */
  for (;;) {
    len = sizeof(struct sockaddr);
    numBytes =
        recvfrom(sfd, buf, BUF_SIZE, 0, (struct sockaddr *)&claddr, &len);
    if (numBytes == -1) errExit("recvfrom");

/* Display address of client that sent the message */
#ifdef IPV6
    if (NULL ==
        inet_ntop(AF_INET6, &claddr.sin_addr, claddrStr, INET6_ADDRSTRLEN)) {
      printf("Couldn't convert client address to string\n");
    } else {
      printf("Server received %ld bytes from (%s, %u)\n", (long)numBytes,
             claddrStr, ntohs(claddr.sin_port));
    }
#else
    if (NULL ==
        inet_ntop(AF_INET, &claddr.sin_addr, claddrStr, INET_ADDRSTRLEN)) {
      printf("Couldn't convert client address to string\n");
    } else {
      printf("Server received %ld bytes from (%s, %u)\n", (long)numBytes,
             claddrStr, ntohs(claddr.sin_port));
    }
#endif

    /*FIXME: above: should use %zd here, and remove (long) cast */
    for (j = 0; j < numBytes; j++) {
      buf[j] = toupper((unsigned char)buf[j]);
    }

    /* send message back to client */
    if (sendto(sfd, buf, numBytes, 0, (struct sockaddr *)&claddr, len) !=
        numBytes) {
      errExit("sendto");
    }
  }
}